#include "Node.h"
/*-----------------------------------------------------------------------------------------------*/
Node::Node( const std::string& name ) : Entity(name)
{
   m_boundingBox = new BoundingBox(Vector3(0,0,0), Vector3(0,0,0));
}
/*-----------------------------------------------------------------------------------------------*/
void Node::addChild( Node* child )
{
   m_childdren.push_back(child);
}
/*-----------------------------------------------------------------------------------------------*/
void Node::removeChild( Node* child )
{
//    for (std::vector<Node*>::iterator it = m_childdren.begin(); it != m_childdren.end(); ++it)
//    {
//       if ( it->getName() == child->getName() )
//       {
//          m_childdren->erase(it);
//       }
//    }
}
/*-----------------------------------------------------------------------------------------------*/
void Node::addMesh( Mesh* mesh )
{
   m_meshes.push_back(mesh);
}
/*-----------------------------------------------------------------------------------------------*/
void Node::draw( Renderer* renderer )
{
   D3DXMatrixIdentity(&m_globalMatrix);
   
   renderer->setMatrixMode(WORLD);
   renderer->loadIdentity();
   
   preDraw(m_globalMatrix, renderer);
   createBoundingBoxes();
   renderer->calculateFrustumPlanes();
   drawMeshes(renderer);

   
}
/*-----------------------------------------------------------------------------------------------*/
void Node::preDraw( Matrix parentMatrix, Renderer* renderer )
{
   Matrix localMatrix;
   D3DXMatrixIdentity(&localMatrix);

   //translation
   Matrix translationMatrix;

   D3DXMatrixTranslation(&translationMatrix, m_position.x, m_position.y, m_position.z); 
   
   D3DXMatrixMultiply(&localMatrix, &translationMatrix, &localMatrix);

   //rotation
   Matrix rotationMatrixX;
   Matrix rotationMatrixY;
   Matrix rotationMatrixZ;

   D3DXMatrixRotationX(&rotationMatrixX, m_rotation.x * 3.14159f / 180.0f);
   D3DXMatrixRotationY(&rotationMatrixY, m_rotation.y * 3.14159f / 180.0f);
   D3DXMatrixRotationZ(&rotationMatrixZ, m_rotation.z * 3.14159f / 180.0f);
   
   D3DXMatrixMultiply(&localMatrix, &rotationMatrixX, &localMatrix);
   D3DXMatrixMultiply(&localMatrix, &rotationMatrixY, &localMatrix);
   D3DXMatrixMultiply(&localMatrix, &rotationMatrixZ, &localMatrix);

   //scale
   Matrix scalingMatrix;
   D3DXMatrixScaling(&scalingMatrix, m_scale.x, m_scale.y, m_scale.z);
   
   D3DXMatrixMultiply(&localMatrix, &scalingMatrix, &localMatrix);

   //////////////////////////////////////////////////////////////////////////
   
   D3DXMatrixMultiply(&localMatrix, &localMatrix, &m_importedMatrix);
   D3DXMatrixMultiply(&m_globalMatrix, &localMatrix, &parentMatrix);

   for (int i = 0 ; i < m_childdren.size(); ++i)
   {
      m_childdren[i]->preDraw(m_globalMatrix, renderer);
   }

}
/*-----------------------------------------------------------------------------------------------*/
void Node::drawMeshes( Renderer* renderer )
{
   if ( !renderer->isBBoxInFrustum(m_boundingBox->calculateBowndingVertices()) )
   {
      //std::cout << "no Dibujando: " << getName() << std::endl;
      return;
   }
   
   renderer->setTransform(m_globalMatrix, WORLD);   
   
   for (int i = 0; i < m_meshes.size(); ++i)
   {
      m_meshes[i]->draw(renderer);
   }

   for (int i = 0; i < m_childdren.size(); ++i)
   {
      m_childdren[i]->drawMeshes(renderer);
   }

   if ( m_boundingBox->isVisible() && m_boundingBox != NULL)
   {
      m_boundingBox->draw(renderer);
   }
   
}
/*-----------------------------------------------------------------------------------------------*/
void Node::createBoundingBoxes()
{
   for (int i = 0 ; i < m_childdren.size(); ++i)
   {
      m_childdren[i]->createBoundingBoxes();
   }

   Vector3 max;
   Vector3 min;

   for (int i = 0; i < m_meshes.size(); ++i)
   {
      Vector3 maxMesh = m_meshes[i]->getBoundingBox()->getMax();
      Vector3 minMesh = m_meshes[i]->getBoundingBox()->getMin();

      if (i == 0)
      {
         max = maxMesh;
         min = minMesh;
         continue;
      }

      compareMaxMinVectors(maxMesh, minMesh, max, min);
   }
   
   //transform the current max and min by the global matrix
   D3DXVec3TransformCoord(&max, &max, &m_globalMatrix);  
   D3DXVec3TransformCoord(&min, &min, &m_globalMatrix); 

   for (int i = 0 ; i < m_childdren.size(); ++i)
   {
      Vector3 maxChild = m_childdren[i]->m_boundingBox->getMax();
      Vector3 minChild = m_childdren[i]->m_boundingBox->getMin();

      if (i == 0 && m_meshes.empty())
      {
         max = maxChild;
         min = minChild;
         continue;
      }

      compareMaxMinVectors(maxChild, minChild, max, min);
   }
   
   m_boundingBox->updateBox(max, min);
}
/*-----------------------------------------------------------------------------------------------*/
/* Max2 & Min2 will have the Max and Min
*/
void Node::compareMaxMinVectors(const Vector3 &max1, const Vector3 &min1, Vector3 &max2, Vector3 &min2)
{
   //X
   if (max1.x > max2.x) max2.x = max1.x;
   if (min1.x < min2.x) min2.x = min1.x;

   if (min1.x > max2.x) max2.x = min1.x;
   if (max1.x < min2.x) min2.x = max1.x;
   
   //Y
   if (max1.y > max2.y) max2.y = max1.y;
   if (min1.y < min2.y) min2.y = min1.y;
   
   if (min1.y > max2.y) max2.y = min1.y;
   if (max1.y < min2.y) min2.y = max1.y;
   
   //Z
   if (max1.z > max2.z) max2.z = max1.z;
   if (min1.z < min2.z) min2.z = min1.z;

   if (min1.z > max2.z) max2.z = min1.z;
   if (max1.z < min2.z) min2.z = max1.z;
}
/*-----------------------------------------------------------------------------------------------*/
Node* Node::getNodeByName( std::string name )
{
   Node* node = NULL;
   recursiveSerchChild(name, &node);
   return node;
}
/*-----------------------------------------------------------------------------------------------*/
void Node::recursiveSerchChild( std::string name, Node** node )
{
   if (getName() == name)
   {
      *node = this;
   }

   for (int i = 0; i < m_childdren.size(); ++i)
   {
      m_childdren[i]->recursiveSerchChild(name, node);
   }  
}

